﻿// <copyright file="DirectoryMapEntryCollection.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;
    using System.Collections.ObjectModel;

    /// <summary>
    /// This class represents a collection of Directory Map Entries.
    /// </summary>
    public class DirectoryMapEntryCollection : KeyedCollection<Guid, DirectoryMapEntry>
    {
        /// <summary>
        /// The GUID of the root directory entry's parent.
        /// </summary>
        /// <remarks>
        /// This is a special value which indicates that, since it is at the root of
        /// the file hierarchy, the root directory entry has no parent item.
        /// </remarks>
        private Guid RootDirectoryEntryParentGuid = new Guid("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF");

        /// <summary>
        /// Initializes a new instance of the DirectoryMapEntryCollection class.
        /// </summary>
        internal DirectoryMapEntryCollection() : base()
        {
        }

        /// <summary>
        /// Finds the Directory Map Entry that represents the root directory.
        /// </summary>
        /// <returns>
        /// Returns a Directory Map Entry that represents the root directory.
        /// If the root directory's map entry cannot be located, null is returned.
        /// </returns>
        public DirectoryMapEntry FindRootEntry()
        {
            for (int i = 0; i < this.Count; i++)
            {
                if (this[i].ParentID == this.RootDirectoryEntryParentGuid)
                {
                    return this[i];
                }
            }

            return null;
        }

        /// <summary>
        /// Finds the child items of the directory map item with the specified GUID.
        /// </summary>
        /// <param name="parentItemGuid">
        /// The GUID of the directory map item whose child items are to be located.
        /// </param>
        /// <returns>
        /// Returns a DirectoryMapEntryCollection containing the child items of
        /// the specified parent item.
        /// </returns>
        public DirectoryMapEntryCollection FindChildItems(Guid parentItemGuid)
        {
            DirectoryMapEntryCollection children = new DirectoryMapEntryCollection();
            for (int i = 0; i < this.Count; i++)
            {
                if (this[i].ParentID == parentItemGuid)
                {
                    children.Add(this[i]);
                }
            }

            return children;
        }

        /// <summary>
        /// Sorts the collection.
        /// </summary>
        public void Sort()
        {
            this.BubbleSort();
        }
        
        /// <summary>
        /// Extracts the key for from the specified element.
        /// </summary>
        /// <param name="item">
        /// The collection element whose key is to be returned.
        /// </param>
        /// <returns>
        /// Returns the key for the specified item.
        /// </returns>
        protected override Guid GetKeyForItem(DirectoryMapEntry item)
        {
            return item.ID;
        }
        
        /// <summary>
        /// Performs a bubble sort on the collection.
        /// </summary>
        private void BubbleSort()
        {
            for (int i = this.Count - 1; i >= 0; i--)
            {
                for (int j = 1; j <= i; j++)
                {
                    if (this[j - 1].EntryType != this[j].EntryType)
                    {
                        if (this[j].EntryType == EntryType.DirectoryEntry)
                        {
                            this.SwapEntries(j - 1, j);
                        }
                    }
                    else if (string.Compare(this[j - 1].LongFileName, this[j].LongFileName, true) > 0)
                    {
                        this.SwapEntries(j - 1, j);
                    }
                }
            }
        }

        /// <summary>
        /// Swaps the items at the two given positions.
        /// </summary>
        /// <param name="left">
        /// The "left" item to be swapped.
        /// </param>
        /// <param name="right">
        /// The "right" item to be swapped.
        /// </param>
        private void SwapEntries(int left, int right)
        {
            DirectoryMapEntry leftItem = this[left];
            DirectoryMapEntry rightItem = this[right];
            this.RemoveAt(right);
            this.RemoveAt(left);
            this.InsertItem(left, rightItem);
            this.InsertItem(right, leftItem);
        }
    }
}
